using System;
using System.Collections;

namespace EnablementManager
{
	/// <summary>
	/// TEnablementManager
	/// </summary>
	public class TEnablementManager
	{
		TEnablements fEnablements = new TEnablements();
		System.Windows.Forms.ToolBarButtonClickEventHandler fToolBarClickDelegate;

		public TEnablementManager()
		{
			//
			// TODO: Add constructor logic here
			//

			fToolBarClickDelegate = new System.Windows.Forms.ToolBarButtonClickEventHandler(ToolbarOnClick);
		}

		private void ProcessChildEnablementsForParent(TEnablement aParentEnablement)
		{
			foreach(TEnablement lEnablement in GetChildEnablementsForParent(aParentEnablement))
			{
				bool lIsEnabled = lEnablement.ProcessEnablement(); // processes itself
				
				// now process its children
				if (lIsEnabled)
					ProcessChildEnablementsForParent(lEnablement);
				else
					TurnOffEnablementsForParent(lEnablement);
			}
		}

		private void TurnOffEnablementsForParent(TEnablement aParentEnablement)
		{
			foreach(TEnablement lEnablement in GetChildEnablementsForParent(aParentEnablement))
			{
				lEnablement.TurnOffEnablement();

				TurnOffEnablementsForParent(lEnablement);
			}
		}

		public void ProcessEnablement()
		{
			ProcessChildEnablementsForParent(null);
		}
			
		public TEnablements Enablements
		{
			get
			{
				return fEnablements;
			}
		}


		public TEnablements GetChildEnablementsForParent(TEnablement aEnablement)
		{
			TEnablements retval = new TEnablements();

			foreach(TEnablement lEnablement in Enablements)
			{
				if (lEnablement.ParentEnablement == aEnablement)
				{
					retval.Add(lEnablement);
				}
			}

			return retval;
		}
	
		public void SetDelegates(string aEnablementName, TEnablementCheckDelegate aCheckDelegate, TEnablementExecuteDelegate aExecuteDelegate)
		{
			TEnablement lEnablement = Enablements.GetEnablementByName(aEnablementName);
			if (lEnablement != null)
			{
				lEnablement.EnablementCheckDelegate = aCheckDelegate;
				lEnablement.EnablementExecuteDelegate = aExecuteDelegate;
			}
		}

		public void ClearDelegates(string aEnablementName)
		{
			SetDelegates(aEnablementName, null, null);
		}

		public TEnablement CreateEnablement(string aEnablementName, TEnablementCheckDelegate aCheckDelegate, TEnablementExecuteDelegate aExecuteDelegate)
		{
			return CreateEnablement(aEnablementName, aCheckDelegate, aExecuteDelegate, aEnablementName, null);
		}

		public TEnablement CreateEnablement(string aEnablementName, TEnablementCheckDelegate aCheckDelegate, TEnablementExecuteDelegate aExecuteDelegate, string aMenuItemText)
		{
			return CreateEnablement(aEnablementName, aCheckDelegate, aExecuteDelegate, aMenuItemText, null);
		}

		public TEnablement CreateEnablement(string aEnablementName, TEnablementCheckDelegate aCheckDelegate, TEnablementExecuteDelegate aExecuteDelegate, TEnablement aParentEnablement)
		{
			return CreateEnablement(aEnablementName, aCheckDelegate, aExecuteDelegate, aEnablementName, aParentEnablement);
		}

		public TEnablement CreateEnablement(
			string aEnablementName, 
			TEnablementCheckDelegate aCheckDelegate, 
			TEnablementExecuteDelegate aExecuteDelegate, 
			string aMenuItemText,
			TEnablement aParentEnablement
			)
		{
			TEnablement lEnablement = new TEnablement();
			lEnablement.EnablementName = aEnablementName;
			lEnablement.EnablementCheckDelegate = aCheckDelegate;
			lEnablement.EnablementExecuteDelegate = aExecuteDelegate;
			lEnablement.MenuItemText = aMenuItemText;
			lEnablement.ParentEnablement = aParentEnablement;
			lEnablement.fOwner = this;
			Enablements.Add(lEnablement);
			return lEnablement;
		}

		public TEnablement CreatePlaceholderEnablement(string aEnablementName, string aMenuItemText)
		{
			return CreateEnablement(aEnablementName, null, null, aMenuItemText, null);
		}

		public TEnablement CreatePlaceholderEnablement(string aEnablementName, string aMenuItemText, TEnablement aParentEnablement)
		{
			return CreateEnablement(aEnablementName, null, null, aMenuItemText, aParentEnablement);
		}

		public TEnablement CreatePlaceholderEnablement(string aEnablementName)
		{
			return CreateEnablement(aEnablementName, null, null, aEnablementName, null);
		}

		public TEnablement CreatePlaceholderEnablement(string aEnablementName, TEnablement aParentEnablement)
		{
			return CreateEnablement(aEnablementName, null, null, aEnablementName, aParentEnablement);
		}

		public void AddControl(string aEnablementName, Object ctl)
		{
			TEnablement lEnablement = Enablements.GetEnablementByName(aEnablementName);
			if (lEnablement != null)
			{
				lEnablement.AddControl(ctl);
			}
		}

		public void RemoveControl(string aEnablementName, Object ctl)
		{
			TEnablement lEnablement = Enablements.GetEnablementByName(aEnablementName);
			if (lEnablement != null)
			{
				lEnablement.RemoveControl(ctl);
			}
		}

		public void AddMenu(System.Windows.Forms.MainMenu aMenu)
		{
			foreach (System.Windows.Forms.MenuItem lMenuItem in aMenu.MenuItems)
			{
				AddMenuItem(lMenuItem);
			}
		}

		public void AddMenuItem(System.Windows.Forms.MenuItem aMenuItem)
		{
			AddControl(aMenuItem.Text, aMenuItem);

			// now add all submenu items
			foreach (System.Windows.Forms.MenuItem lMenuItem in aMenuItem.MenuItems)
			{
				AddMenuItem(lMenuItem);
			}
		}

		public void RemoveMenu(System.Windows.Forms.MainMenu aMenu)
		{
			foreach (System.Windows.Forms.MenuItem lMenuItem in aMenu.MenuItems)
			{
				RemoveMenuItem(lMenuItem);
			}
		}

		public void RemoveMenuItem(System.Windows.Forms.MenuItem aMenuItem)
		{
			RemoveControl(aMenuItem.Text, aMenuItem);

			// now add all submenu items
			foreach (System.Windows.Forms.MenuItem lMenuItem in aMenuItem.MenuItems)
			{
				RemoveMenuItem(lMenuItem);
			}
		}

		public void AddContextMenu(System.Windows.Forms.ContextMenu aContextMenu)
		{
			foreach (System.Windows.Forms.MenuItem lMenuItem in aContextMenu.MenuItems)
			{
				AddMenuItem(lMenuItem);
			}
		}

		public void RemoveContextMenu(System.Windows.Forms.ContextMenu aContextMenu)
		{
			foreach (System.Windows.Forms.MenuItem lMenuItem in aContextMenu.MenuItems)
			{
				RemoveMenuItem(lMenuItem);
			}
		}

		public void AddToolbar(System.Windows.Forms.ToolBar aToolbar)
		{
			foreach(System.Windows.Forms.ToolBarButton lButton in aToolbar.Buttons)
			{
				if ((lButton.Tag != null) && (lButton.Tag is String))
					AddControl(lButton.Tag as String, lButton);
			}

			// Now set up the execution handler
			aToolbar.ButtonClick += fToolBarClickDelegate;
		}

		private void ToolbarOnClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)
		{
			if ((e.Button != null) && (e.Button.Tag != null) && (e.Button.Tag is String))
			{
				TEnablement lEnablement = Enablements.GetEnablementByName(e.Button.Tag as string);
				if (lEnablement != null)
				{
					lEnablement.Execute();
				}
			}
		}

		public void RemoveToolbar(System.Windows.Forms.ToolBar aToolbar)
		{
			foreach(System.Windows.Forms.ToolBarButton lButton in aToolbar.Buttons)
			{
				if ((lButton.Tag != null) && (lButton.Tag is String))
					RemoveControl(lButton.Tag as String, lButton);
			}

			// Now clear the execution handler
			aToolbar.ButtonClick -= fToolBarClickDelegate;
		}

		public void AddButton(System.Windows.Forms.Button aButton)
		{
			if ((aButton.Tag != null) && (aButton.Tag is String))
				AddControl(aButton.Tag as String, aButton);
		}

		public void RemoveButton(System.Windows.Forms.Button aButton)
		{
			if ((aButton.Tag != null) && (aButton.Tag is String))
				RemoveControl(aButton.Tag as String, aButton);
		}

		public void AddControlButtons(System.Windows.Forms.Control aControl)
		{
			foreach (System.Windows.Forms.Control lControl in aControl.Controls)
			{
				if (lControl is System.Windows.Forms.Button)
					AddButton(lControl as System.Windows.Forms.Button);
				AddControlButtons(lControl);
			}
		}

		public void RemoveControlButtons(System.Windows.Forms.Control aControl)
		{
			foreach (System.Windows.Forms.Control lControl in aControl.Controls)
			{
				if (lControl is System.Windows.Forms.Button)
					RemoveButton(lControl as System.Windows.Forms.Button);
				RemoveControlButtons(lControl);
			}
		}

		public void AddFormButtons(System.Windows.Forms.Form aForm)
		{
			AddControlButtons(aForm);
		}

		public void RemoveFormButtons(System.Windows.Forms.Form aForm)
		{
			RemoveControlButtons(aForm);
		}

		public bool IsEnabled(string aEnablementName)
		{
			bool retval = false;

			TEnablement lEnablement = Enablements.GetEnablementByName(aEnablementName);
			if (lEnablement != null)
				retval = lEnablement.IsEnabled;

			return retval;
		}
	}

	public class TEnablements : CollectionBase  
	{
		private void Constructor()
		{
		}

		public TEnablements(): base()
		{
		}


		public TEnablement this[ int index ]  
		{
			get  
			{
				return( (TEnablement) List[index] );
			}
			set  
			{
				if (List[index] != value)
				{
					List[index] = value;
				}	
			}
		}

		public int Add( TEnablement value )  
		{
			int retval = List.Add( value );
			return( retval );
		}

		public int IndexOf( TEnablement value )  
		{
			return( List.IndexOf( value ) );
		}

		public void Insert( int index, TEnablement value )  
		{
			List.Insert( index, value );
		}

		public void Remove( TEnablement value )  
		{
			List.Remove( value );
		}

		public bool Contains( TEnablement value )  
		{
			// If value is not of type TEnablement, this will return false.
			return( List.Contains( value ) );
		}

		protected override void OnInsert( int index, Object value )  
		{
			if ( value.GetType() != Type.GetType("EnablementManager.TEnablement") )
				throw new ArgumentException( "value must be of type TEnablement.", "value" );
		}

		protected override void OnRemove( int index, Object value )  
		{
			if ( value.GetType() != Type.GetType("EnablementManager.TEnablement") )
				throw new ArgumentException( "value must be of type TEnablement.", "value" );
		}

		protected override void OnSet( int index, Object oldValue, Object newValue )  
		{
			if ( newValue.GetType() != Type.GetType("EnablementManager.TEnablement") )
				throw new ArgumentException( "newValue must be of type TEnablement.", "newValue" );
		}

		protected override void OnValidate( Object value )  
		{
			if ( value.GetType() != Type.GetType("EnablementManager.TEnablement") )
				throw new ArgumentException( "value must be of type TEnablement." );
		}

		public TEnablement GetEnablementByName(string aEnablementName)
		{
			TEnablement retval = null;

			foreach (TEnablement lEnablement in this)
			{
				if (lEnablement.EnablementName.ToUpper().Equals(aEnablementName.ToUpper()))
				{
					retval = lEnablement;
					break;
				}
			}

			return retval;
		}
	}

	public delegate void TEnablementCheckDelegate(ref bool aIsEnabled);
	public delegate void TEnablementExecuteDelegate();

	public class TEnablement
	{
		private string fEnablementName = "";
		private string fMenuItemText = "";
		private ArrayList fControls = new ArrayList();
		private TEnablementCheckDelegate fEnablementCheckDelegate = null;
		private TEnablementExecuteDelegate fEnablementExecuteDelegate = null;
		private System.EventHandler fOnClick1Delegate = null;
		internal TEnablementManager fOwner;
		private TEnablement fParentEnablement = null;

		public TEnablement()
		{
			fOnClick1Delegate = new System.EventHandler(OnClick1);
		}

		public bool LocalIsEnabled
		{
			get
			{
				bool retval = false;

				// if no parents or parents are enabled, check self.
				if (fEnablementCheckDelegate != null)
				{
					fEnablementCheckDelegate(ref retval);
				}
				
				return retval;
			}
		}

		public bool IsEnabled
		{
			get
			{
				bool retval;

				// first check parents
				if (fParentEnablement != null)
					retval = fParentEnablement.IsEnabled;
				else
					retval = true; // ie: no parent to make it false

				if (retval) 
					retval = LocalIsEnabled;

				return retval;
			}
		}

		public void DoExecute()
		{
			if ((fEnablementExecuteDelegate != null) && IsEnabled)
			{
				using (new TBusyCursorScope())
				{
					fEnablementExecuteDelegate();
					if (fOwner != null)
						fOwner.ProcessEnablement();
				}
			}
		}

		public bool ProcessEnablement()
		{
			bool lIsEnabled = LocalIsEnabled;

			foreach(Object ctl in fControls)
			{
				if (ctl is System.Windows.Forms.Control)
				{
					(ctl as System.Windows.Forms.Control).Enabled = lIsEnabled;
				}
				else if (ctl is System.Windows.Forms.ToolBarButton)
				{
					(ctl as System.Windows.Forms.ToolBarButton).Enabled = lIsEnabled;
				}
				else if (ctl is System.Windows.Forms.MenuItem)
				{
					(ctl as System.Windows.Forms.MenuItem).Enabled = lIsEnabled;
				}
			}

			return lIsEnabled;
		}

		public void TurnOffEnablement()
		{
			foreach(Object ctl in fControls)
			{
				if (ctl is System.Windows.Forms.Control)
				{
					(ctl as System.Windows.Forms.Control).Enabled = false;
				}
				else if (ctl is System.Windows.Forms.ToolBarButton)
				{
					(ctl as System.Windows.Forms.ToolBarButton).Enabled = false;
				}
				else if (ctl is System.Windows.Forms.MenuItem)
				{
					(ctl as System.Windows.Forms.MenuItem).Enabled = false;
				}
			}
		}

		private void OnClick1(
			object sender,
			EventArgs e
			)
		{
			DoExecute();
		}

		public void Execute()
		{
			DoExecute();
		}

		internal void WireUpControl(Object ctl)
		{
//			if (fOnClick1Delegate == null)
//				fOnClick1Delegate = new EventHandler(OnClick1);

			if (ctl is System.Windows.Forms.Control)
			{
				(ctl as System.Windows.Forms.Control).Click += fOnClick1Delegate;
			}
				//			else if (ctl is System.Windows.Forms.ToolBarButton)
				//			{
				//				(ctl as System.Windows.Forms.ToolBarButton).Enabled = lIsEnabled;
				//			}
			else if (ctl is System.Windows.Forms.MenuItem)
			{
				(ctl as System.Windows.Forms.MenuItem).Click += fOnClick1Delegate;
				(ctl as System.Windows.Forms.MenuItem).Text = MenuItemText;
			}
		}

		internal void UnwireControl(Object ctl)
		{
			if (ctl is System.Windows.Forms.Control)
			{
				(ctl as System.Windows.Forms.Control).Click -= fOnClick1Delegate;
			}
				//			else if (ctl is System.Windows.Forms.ToolBarButton)
				//			{
				//				(ctl as System.Windows.Forms.ToolBarButton).Enabled = lIsEnabled;
				//			}
			else if (ctl is System.Windows.Forms.MenuItem)
			{
				(ctl as System.Windows.Forms.MenuItem).Click -= fOnClick1Delegate;
				(ctl as System.Windows.Forms.MenuItem).Text = EnablementName;
			}
		}

		public string EnablementName
		{
			get
			{
				return fEnablementName;
			}
			set
			{
				fEnablementName = value;
			}
		}

		public string MenuItemText
		{
			get
			{
				return fMenuItemText;
			}
			set
			{
				fMenuItemText = value;
			}
		}

		public void AddControl(Object ctl)
		{
			if ((ctl != null) && (!fControls.Contains(ctl)))
			{
				fControls.Add(ctl);
				WireUpControl(ctl);
			}
		}

		public void RemoveControl(Object ctl)
		{
			if ((ctl != null) && (fControls.Contains(ctl)))
			{
				UnwireControl(ctl);
				fControls.Remove(ctl);
			}
		}

		public TEnablementCheckDelegate EnablementCheckDelegate
		{
			get
			{
				return fEnablementCheckDelegate;
			}
			set
			{
				fEnablementCheckDelegate = value;
			}
		}

		public TEnablementExecuteDelegate EnablementExecuteDelegate
		{
			get
			{
				return fEnablementExecuteDelegate;
			}
			set
			{
				fEnablementExecuteDelegate = value;
			}
		}

		public TEnablement ParentEnablement
		{
			get
			{
				return fParentEnablement;
			}
			set
			{
				fParentEnablement = value;
			}
		}
	}
}
